package cn.slipi.admin.interceptor;

import cn.slipi.admin.common.annotation.NoLogin;
import cn.slipi.admin.common.annotation.Permission;
import cn.slipi.admin.common.exception.base.BizException;
import cn.slipi.admin.common.utils.cache.redis.RedisClient;
import cn.slipi.admin.constants.AdminConstants;
import cn.slipi.admin.context.dto.PermissionInfo;
import cn.slipi.admin.context.dto.VisitorInfo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 认证验证
 * 判断接口是否使用NoLogin注解若使用则放行，判断用户是否登陆若登陆将用户信息设置进入上下文（ManageThreadContext）
 */

@Component
public class PermissionInterceptor implements HandlerInterceptor {


    @Autowired
    private RedisClient redisClient;

    private static final Logger LOG = LoggerFactory.getLogger(PermissionInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Class<?> clazz = handlerMethod.getBeanType();
        Method m = handlerMethod.getMethod();
        // 接口是否需要权限
        Boolean canAccess = false;
        if (needPermission(clazz, m)) {
            //需要校验权限
            String token = request.getHeader(AdminConstants.TOKEN_KEY);
            if (StringUtils.isBlank(token)) {
                token = request.getParameter(AdminConstants.TOKEN_KEY);
            }
            VisitorInfo visitorInfo = this.redisClient.get(token, VisitorInfo.class);
            //超级管理员
            if (visitorInfo.getIsAdmin().equals(1)) {
                canAccess = true;
            } else {
                Permission permission = handlerMethod.getMethod().getAnnotation(Permission.class);
                List<String> checkPermissions = Arrays.asList(permission.value());
                //用户权限
                List<PermissionInfo> permissionList = visitorInfo.getPermissions();
                if (null != permissionList && permissionList.size() > 0) {
                    List<String> userHasPermissions = permissionList.stream().map(PermissionInfo::getAction).collect(Collectors.toList());
                    for (String checkPermission : checkPermissions) {
                        if (userHasPermissions.contains(checkPermission.toLowerCase())) {
                            canAccess = true;
                        }
                    }
                } else {
                    if (checkPermissions.size() == 0) {
                        canAccess = true;
                    }
                }
            }
        } else {
            //无需校验权限
            canAccess = true;
        }
        if (canAccess) {
            return true;
        }
        throw new BizException(403, "permission.not.oper");
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }

    /**
     * 是否需要权限
     *
     * @param m handler method
     * @return
     */
    private boolean needPermission(Class<?> clazz, Method m) {
        if (clazz.isAnnotationPresent(NoLogin.class) || m.isAnnotationPresent(NoLogin.class)) {
            return false;
        } else {
            return m.isAnnotationPresent(Permission.class);
        }
    }
}
